package com.anuo.app.common.utils;

import com.anuo.app.common.basedata.Platforms;
import com.anuo.app.common.entity.NotNull;
import com.anuo.app.common.entity.Nullable;
import com.anuo.app.common.globalhandle.GlobalConfig;

import com.google.common.io.Files;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;

import java.io.*;
import java.util.Iterator;

/**
 * 文件操作工具类
 * 参考:
 * 参考的是springside 的FileUtil, 如有更多需求,请访问此项目的原文件
 */
public class FileUtil extends org.apache.commons.io.FileUtils {

    /**
     * 写入String到File. 如果没有文件会创建文件
     */
    public static void writeString(final CharSequence data, final File file) throws IOException {
        Files.write(data, file, GlobalConfig.UTF_8);
    }

    /**
     * 写入String到File.
     *
     * @param data
     * @param filePath
     * @throws IOException
     */
    public static void writeString(final CharSequence data, String filePath) throws IOException {
        File file = new File(filePath);
        Files.write(data, file, GlobalConfig.UTF_8);
    }

    /**
     * 读取文件到String.
     */
    public static String readToString(final File file) throws IOException {
        return Files.toString(file, GlobalConfig.UTF_8);
    }

    /**
     * 读取文件到String.
     */
    public static String readToString(String filePath) throws IOException {
        File file = new File(filePath);
        return Files.toString(file, GlobalConfig.UTF_8);
    }


    /**
     * 追加String到File.
     */
    public static void appendString(final CharSequence from, final File to) throws IOException {
        Files.append(from, to, GlobalConfig.UTF_8);
    }

    /**
     * 追加String到File.
     */
    public static void appendString(CharSequence from, String toFilePath) throws IOException {
        File to = new File(toFilePath);
        Files.append(from, to, GlobalConfig.UTF_8);

    }

    /**
     * 复制文件或目录
     *
     * @param from 如果为null，或者是不存在的文件或目录，抛出异常.
     * @param to   如果为null，或者from是目录而to是已存在文件，或相反
     */
    public static void copy(@NotNull File from, @NotNull File to) throws IOException {
        Validate.notNull(from);
        Validate.notNull(to);

        if (from.isDirectory()) {
            copyDir(from, to);
        } else {
            copyFile(from, to);
        }
    }

    /**
     * 文件复制.
     *
     * @param from 如果为nll，或文件不存在或者是目录，，抛出异常
     * @param to   如果to为null，或文件存在但是一个目录，抛出异常
     */
    public static void copyFile(@NotNull File from, @NotNull File to) throws IOException {
        Validate.isTrue(isFileExists(from), from + " is not exist or not a file");
        Validate.notNull(to);
        Validate.isTrue(!FileUtil.isDirExists(to), to + " is exist but it is a dir");
        Files.copy(from, to);
    }

    /**
     * 复制目录
     */
    public static void copyDir(@NotNull File from, @NotNull File to) throws IOException {
        Validate.isTrue(isDirExists(from), from + " is not exist or not a dir");
        Validate.notNull(to);

        if (to.exists()) {
            Validate.isTrue(!to.isFile(), to + " is exist but it is a file");
        } else {
            to.mkdirs();
        }

        File[] files = from.listFiles();
        if (files != null) {
            for (int i = 0; i < files.length; i++) {
                String name = files[i].getName();
                if (".".equals(name) || "..".equals(name)) {
                    continue;
                }
                copy(files[i], new File(to, name));
            }
        }
    }

    /**
     * 删除文件.
     * <p>
     * 如果文件不存在或者是目录，则不做修改
     */
    public static void deleteFile(@Nullable File file) throws IOException {
        Validate.isTrue(isFileExists(file), file + " is not exist or not a file");
        file.delete();
    }

    /**
     * 删除文件.
     * <p>
     * 如果文件不存在或者是目录，则不做修改
     */
    public static void deleteFile(@Nullable String filePath) throws IOException {
        File file = new File(filePath);
        Validate.isTrue(isFileExists(file), file + " is not exist or not a file");
        file.delete();
    }


    /**
     * 删除目录及所有子目录/文件
     */
    public static void deleteDir(File dir) {
        Validate.isTrue(isDirExists(dir), dir + " is not exist or not a dir");

        // 后序遍历，先删掉子目录中的文件/目录
        Iterator<File> iterator = Files.fileTreeTraverser().postOrderTraversal(dir).iterator();
        while (iterator.hasNext()) {
            iterator.next().delete();
        }
    }

    /**
     * 判断目录是否存在
     */
    public static boolean isDirExists(String dirPath) {
        return isDirExists(getFileByPath(dirPath));
    }

    /**
     * 判断目录是否存在
     */
    public static boolean isDirExists(File dir) {
        if (dir == null) {
            return false;
        }
        return dir.exists() && dir.isDirectory();
    }

    /**
     * 确保目录存在, 若不存在则创建
     */
    public static void makesureDirExists(String dirPath) throws IOException {
        makesureDirExists(getFileByPath(dirPath));
    }

    /**
     * 确保目录存在, 若不存在则创建
     */
    public static void makesureDirExists(File file) throws IOException {
        Validate.notNull(file);
        if (file.exists()) {
            if (!file.isDirectory()) {
                throw new IOException("There is a file exists " + file);
            }
        } else {
            file.mkdirs();
        }
    }

    /**
     * 判断文件是否存在
     */
    public static boolean isFileExists(String fileName) {
        return isFileExists(getFileByPath(fileName));
    }

    /**
     * 判断文件是否存在
     */
    public static boolean isFileExists(File file) {
        if (file == null) {
            return false;
        }
        return file.exists() && file.isFile();
    }

    private static File getFileByPath(String filePath) {
        return StringUtils.isBlank(filePath) ? null : new File(filePath);
    }

    /**
     * 获取文件名(不包含路径)
     */
    public static String getFileName(@NotNull String fullName) {
        Validate.notEmpty(fullName);
        int last = fullName.lastIndexOf(File.separatorChar);
        return fullName.substring(last + 1);
    }

    /**
     * 获取文件名的扩展名部分(不包含.)
     */
    public static String getFileExtension(File file) {
        return Files.getFileExtension(file.getName());
    }

    /**
     * 获取文件名的扩展名部分(不包含.)
     */
    public static String getFileExtension(String fullName) {
        return Files.getFileExtension(fullName);
    }

    /**
     * 合并多个路径
     * @param pathArray
     * @return
     */
    public static String combinePath(String... pathArray) {
        String result = "";
        for (String path : pathArray) {
            result += path + Platforms.FILE_PATH_SEPARATOR_CHAR;
        }
        result = StringUtils.removeEnd(result, Character.toString(Platforms.FILE_PATH_SEPARATOR_CHAR));
        return result;
    }

}
